﻿''' <summary>
''' Classe regroupant des méthodes de projections actuarielles
''' </summary>
''' <remarks>Pour une projection : 1 fonction de calcul qui remplit une liste de couple(tableau, type du tableau)
'''1 fonction qui crée une dataTable
'''1 liste de projections en entrée</remarks>
Public Module ProjectionsActuariat

#Region "Pour abstraction de la notion de projection"

    ''' <summary>
    ''' Délégué représentant une foction de projection
    ''' </summary>
    ''' <param name="parametres">Données en entrées</param>
    ''' <returns>Résultats des calculs</returns>
    ''' <remarks></remarks>
    Public Delegate Function TypeFonctionProjection(ByVal parametres As Object) As Object


    'Public MustInherit Class projection
    'Structure Resultat
    ' .type as type.getType()
    ' .table résultat
    'End structure
    'Protected _parametre As Dictionary(Of String, Object)
    'Protected _fonctionProjection As typeFonctionProjection
    'Public Sub executeCalcule()
    '    _fonctionProjection.Invoke(_parametre)
    '    Utiliser les noms des paramètres dans la fonction de calcule
    'End Sub
    'End Class
#End Region

#Region "Indices de période"
    ''' <summary>
    ''' Renvoie un tableau d'integer à une dimension contenant les N° de mois de 1 à nbPer
    ''' </summary>
    ''' <param name="nbPer">Nombre de périodes de projection</param>
    ''' <returns>Tableau d'integer à une dimension contenant les N° de période de 1 à nbPer</returns>
    ''' <remarks></remarks>
    Public Function Proj_Num_Periodes(ByVal nbPer As Integer) As Integer()
        Dim result(nbPer - 1) As Integer
        For i As Integer = 0 To nbPer - 1
            result(i) = i + 1
        Next i
        Return result
    End Function

    ''' <summary>
    '''  Renvoie un tableau à une dimension,en supposant que la projection est mensuelle, des années pleines correspondant à chaque mois
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <returns>Tableau d'integer à une dimension contenant les N° de période de 1 à nbPer</returns>
    ''' <remarks></remarks>
    Public Function Proj_Num_Annee(ByVal nbPer As Integer) As Integer()
        Dim result(nbPer - 1) As Integer
        For i = 1 To nbPer
            result(i - 1) = Math.Ceiling(i / 12)
            'If Fix(i / 12) <> i / 12 Then result(i - 1) = Fix(i / 12) + 1 Else result(i - 1) = Fix(i / 12)
        Next i
        Return result
    End Function

    ''' <summary>
    ''' Tableau à une dimension, qui renvoie pour une projection mensuelle =1 si le mois correspond à une année pleine et 0 sinon
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <returns>Tableau d'integer à une dimension contenant les N° de période de 1 à nbPer</returns>
    ''' <remarks></remarks>
    Public Function Proj_Ind_AnneesPleines(ByVal nbPer As Integer) As Integer()
        Dim result(nbPer - 1) As Integer
        For i = 1 To nbPer
            If Fix(i / 12) = i / 12 Then result(i - 1) = 1 Else result(i - 1) = 0
        Next i
        Return result
    End Function
#End Region

#Region "Echéancier"
    ''' <summary>
    '''Cette fonction permet de recalculer l'échéancier d'un emprunt
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="CI">Capital Initial</param>
    ''' <param name="txNomPer"></param>
    ''' <param name="vision">Mode projection</param>
    ''' <param name="terme">Type de terme</param>
    ''' <returns>Echéancier d'un emprunt</returns>
    ''' <remarks>Cette fonction permet de recalculer l'échéancier d'un emprunt, hors assurance,
    '''et renvoie le résultat sous forme de tableau
    '''   - nbPer = le nombre de périodes
    '''   - CI = le capital initial
    '''   - txNomPer = le taux nominal du prêt sur la période
    '''   - vision = Vision fin de période (="Fin per") / Début de période (="Deb per")
    '''   - terme = Paiement des primes à terme (="A terme") / d'avance (="D'avance")
    '''   - hauteur = hauteur du tableau résultat pour intégration dans une feuille EXCEL 
    ''' </remarks>
    Public Function Proj_Echeancier(ByVal nbPer As Integer, _
                                    ByVal CI As Double, _
                                    ByVal txNomPer As Double, _
                                    ByVal vision As TypeVision, _
                                    ByVal terme As TypeTerme) As Double()

        'Définition des variables utilisées pour la projection
        Dim result(nbPer - 1) As Double

        If terme = TypeTerme.TERME Then
            'Calcul des CRD en cas de paiement des primes à terme
            For i = 1 To nbPer
                result(i - 1) = CI * ((1 + txNomPer) ^ nbPer - (1 + txNomPer) ^ i) / ((1 + txNomPer) ^ nbPer - 1)
            Next i
            If vision = TypeVision.DEBPER Then
                Dim result1(0 To nbPer - 1)
                For i = 2 To nbPer
                    result1(i - 1) = result(i - 2)
                Next i
                result1(0) = CI
                For i = 1 To nbPer
                    result(i - 1) = result1(i - 1)
                Next i
            End If
        End If

        If terme = TypeTerme.AVANCE Then
            'Calcul des CRD en cas de paimement des primes d'avance
            For i = 1 To nbPer
                result(i - 1) = CI * (1 + txNomPer) ^ (i - 1) - (CI * ((1 + txNomPer) ^ (nbPer - 1) / (1 - (1 + txNomPer) ^ nbPer))) * (1 - (1 + txNomPer) ^ i)
            Next i
        End If

        'Retour du résultat
        Return result

    End Function
#End Region

#Region "Ages des assurés"
    ''' <summary>
    ''' Renvoie le tableau des âges exactes en années à partir d'un âge initial et d'un nombre de période
    ''' </summary>
    ''' <param name="ageInit">Age Initiale</param>
    ''' <param name="nbPer">Nombre de période</param>
    ''' <returns>Tableau des âges exactes</returns>
    ''' <remarks></remarks>
    Public Function Proj_Ages(ByVal ageInit As Double, ByVal nbPer As Integer) As Double()

        Dim ages(nbPer - 1) As Double, n As Integer

        'Calcul de l'âge en milieu de chaque période
        For n = 1 To nbPer
            'Calcul des âges actuariels au milieu de chaque période - Enregistrement dans la première colonne
            ages(n - 1) = ageInit + (n / 12 - 1 / 24)
        Next n

        Return ages

    End Function
#End Region

#Region "Abattements liés à la sélection médicale"
    ''' <summary>
    ''' Projection des abattements liés à la sélection médicale
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="sel_med">Sélection Médicale</param>
    ''' <returns>Résultat</returns>
    ''' <remarks></remarks>
    Public Function Proj_Abt_Sel_Med(ByVal nbPer As Integer, ByVal sel_med As Double()) As Double()

        Dim coef_borneMin, coef_borneMax As Double
        Dim selMed_borneMin, selMed_borneMax As Double
        Dim sel_med_per(nbPer - 1) As Double

        For n As Integer = 1 To nbPer

            coef_borneMin = 1 - (n / 12 - (Int(n / 12)))
            coef_borneMax = 1 - coef_borneMin
            If Int(n / 12) > sel_med.Count - 1 Then
                selMed_borneMin = 0
            Else
                selMed_borneMin = sel_med(Int(n / 12))
            End If

            If Int(n / 12) + 1 > sel_med.Count - 1 Then
                selMed_borneMax = 0
            Else
                selMed_borneMax = sel_med(Int(n / 12) + 1)
            End If

            sel_med_per(n - 1) = coef_borneMin * selMed_borneMin + coef_borneMax * selMed_borneMax

        Next n

        Return sel_med_per
    End Function
#End Region

#Region "Taux de mortalité"

    ''' <summary>
    ''' Calcul des taux de mortalité au milieu de chaque période à partir des taux annuels
    ''' </summary>
    ''' <param name="ages">Tableau représentant les âges à chaque période</param>
    ''' <param name="txMortAn">Taux de mortalité annuels à appliquer à chaque âge</param>
    ''' <param name="sel_medicale">Taux d'abattement annuels sur la mortalité liés à la sélection médicale</param>
    ''' <param name="nbPer">Nombre de période de projection</param>
    ''' <param name="presence_sel_medic">Prise en compte de la sélection médicale</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_Mortalites(ByVal ages As Double(), _
                                    ByVal txMortAn As Double(,), _
                                    ByVal sel_medicale As Double(), _
                                    ByVal nbPer As Integer, _
                                    ByVal presence_sel_medic As Boolean) As Double()

        Dim tx_mortaliteMilieuPeriode(nbPer - 1) As Double
        Dim coef_borneMin As Double, coef_borneMax As Double

        For n = 1 To nbPer

            'Lissage des taux
            coef_borneMin = 1 - (ages(n - 1) - Int(ages(n - 1)))
            coef_borneMax = 1 - coef_borneMin
            tx_mortaliteMilieuPeriode(n - 1) = coef_borneMin * txMortAn(Int(ages(n - 1)), 1) + coef_borneMax * txMortAn(Int(ages(n - 1)) + 1, 1)

        Next n

        'Calcul des taux de mortalité comprenant la sélection médicale
        If presence_sel_medic Then
            Dim sel_med_per As Double() = Proj_Abt_Sel_Med(nbPer, sel_medicale)
            sel_med_per = Moy_Mobile(sel_med_per, 5)
            For n = 1 To nbPer
                tx_mortaliteMilieuPeriode(n - 1) = tx_mortaliteMilieuPeriode(n - 1) * (1 - sel_med_per(n - 1))
            Next n
        End If

        Return tx_mortaliteMilieuPeriode

    End Function
#End Region

#Region "Nombre de cotisants"

    ''' <summary>
    ''' Projection des nombres de cotisants. 
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="nbEmprInit">Emprunt Initial</param>
    ''' <param name="txRemb">Taux de remboursement</param>
    ''' <param name="tx_mortalite">Taux de mortalité</param>
    ''' <returns>La première colonne représente le nombre de cotisants en début de période
    ''' et la deuxième colonne représente le nombre de cotisants en fin de période
    ''' </returns>
    ''' <remarks></remarks>
    Public Function Proj_Cotisants(ByVal nbPer As Integer, _
                                   ByVal nbEmprInit As Double, _
                                   ByVal txRemb As Double, _
                                   ByVal tx_mortalite As Double()) As Double(,)

        Dim nb_cotisants(nbPer - 1, 1) As Double

        'initialisation
        nb_cotisants(0, 0) = nbEmprInit

        'Calcul de l'évolution des nombres de cotisants
        For n = 1 To nbPer - 1

            'Calcul du nombre de cotisants en début de période n
            nb_cotisants(n, 0) = (1 - tx_mortalite(n - 1)) * nb_cotisants(n - 1, 0) * (1 - txRemb)
            'Calul du nombre de cotisants en fin de période n-1
            nb_cotisants(n - 1, 1) = nb_cotisants(n, 0)

        Next n

        nb_cotisants(nbPer - 1, 1) = (1 - tx_mortalite(nbPer - 1)) * nb_cotisants(nbPer - 1, 0) * (1 - txRemb)

        Return nb_cotisants

    End Function

#End Region

#Region "Nombre d'individus en incapacité/invalidité"

    ''' <summary> 
    '''  Cette fonction permet de projeter l'évolution des nombres d'individus en sinistre INCAP/INVAL  
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="nbInitEmpr">Emprunt Initial</param>
    ''' <param name="tx_entree_INCINV">taux d'entrée en incapacité invalidité</param>
    ''' <param name="ages">Tableau des ages</param>
    ''' <param name="cotisants">Tableau es  cotisants</param>
    ''' <returns></returns>
    ''' <remarks> Cette fonction permet de projeter l'évolution des nombres d'individus en sinistre INCAP/INVAL
    ''' Elle renvoie un tableau contenant 2 éléments.
    ''' 
    '''    - Le 1er élément contient un tableau à 4 colonnes :
    '''        - 1ere colonne (indice 0) : nb individus valides en début de période (en tenant compte des franchises)
    '''        - 2eme colonne (indice 1) : nb individus valides en fin de période (en tenant compte des franchises)
    '''        - 3ème colonne (indice 2) : nb individus en incap inval en début de période (en tenant compte des franchises)
    '''        - 4ème colonne (indice 3) : nb individus en incap inval en fin de période (en tenant compte des franchises)
    '''
    '''    - le 2eme tableau contient le nombre d'individus dont l'incapacité est survenue au mois i toujours en incap/inval au mois n (sans tenir compte des franchises)
    '''        - les survenances sont en ligne et les périodes d'observation en colonne.
    ''' </remarks>
    Public Function Proj_Nb_INCINV(ByVal nbPer As Integer, _
                                   ByVal nbInitEmpr As Double, _
                                   ByVal tx_entree_INCINV As Double, _
                                   ByVal ages As Double(), _
                                   ByVal cotisants As Double(,), _
                                   ByVal tableMaintienINCINV As ITableMaintienINCAPINVAL) As Object

        'nb_ind_INC_INV contient les nombres d'individus en incap/inval (hors franchise) par survenance et fin d'année d'observation
        'nb_inc_inv_evol contient l'évolution des nombres de valides et sinistrés (après franchise) par année d'observation
        Dim nb_ind_INC_INV(nbPer - 1, nbPer - 1) As Double
        Dim nb_incinv_evol(nbPer - 1, 3) As Double
        Dim result(1) As Object

        nb_incinv_evol(0, 0) = nbInitEmpr

        Dim ageSurv As Double, nbMoisMaintien As Integer, tx_maintien As Double

        'Période d'observation
        For n = 1 To nbPer

            'Pour toutes les survenances i antérieures à la période d'observation
            For i = 1 To n - 1
                'L'âge à la survenance i est le suivant (le 1er indice du tableau des âges =0 ce qui explique le -1) :
                ageSurv = ages(i - 1)
                'Le nombre de mois de maintien en sinistre à la date d'observation est le suivant
                'Le +1 vient du fait que l'on suppose que les entrées interviennent en début de mois
                nbMoisMaintien = n - i + 1
                'La proba de maintien en incap inval en n pour une entrée à la survenance i s'écrit donc :
                tx_maintien = tableMaintienINCINV.Proba_Maintien(nbMoisMaintien, ageSurv)
                'On en déduit le nombre d'individus en incap/inval en n dont le sinistre est survenu en i
                nb_ind_INC_INV(i - 1, n - 1) = nb_incinv_evol(i - 1, 0) * tx_entree_INCINV * tx_maintien
            Next i

            nb_ind_INC_INV(n - 1, n - 1) = nb_incinv_evol(n - 1, 0) * tx_entree_INCINV * tableMaintienINCINV.Proba_Maintien(1, ages(n - 1))

            'Le nombre de valides en fin de période est égal au nombre de cotisants fin de période
            '- nb sinistrés après période de franchise
            Dim nb_sin_incinv As Integer = 0

            'Ici, on calcule le nombre d'individus en INCAP/INVAL en fin de période n
            For i = 1 To n - 3
                'Le nombre d'individus en INCAP/INVAL en fin de période n est égal à la somme de tous
                'les individus entrés en INCAP/INVAL avant n et qui ont dépassé la franchise
                nb_incinv_evol(n - 1, 3) = nb_incinv_evol(n - 1, 3) + nb_ind_INC_INV(i - 1, n - 1)
            Next i

            'Ici on calcul le nombre d'individus valides en fin de période n
            nb_incinv_evol(n - 1, 1) = cotisants(n - 1, 1) - nb_incinv_evol(n - 1, 3)

            'Ici on initialise les nombres d'individus valides (colonne 0)
            'et les nombres d'individus en sinistre (colonne 2) en début de période n+1 (indice n dans le tableau)
            If n < nbPer Then
                nb_incinv_evol(n, 0) = nb_incinv_evol(n - 1, 1)
                nb_incinv_evol(n, 2) = nb_incinv_evol(n - 1, 3)
            End If

            Dim b As Boolean = (n = 210)
        Next n

        result(0) = nb_incinv_evol
        result(1) = nb_ind_INC_INV

        Proj_Nb_INCINV = result

    End Function

#End Region

#Region "Cotisations"
    ''' <summary>
    '''  Cette fonction permet de projeter les cotisations commerciales DC
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="CI">Cappitall Initial</param>
    ''' <param name="ages">Ages</param>
    ''' <param name="echeancier_deb">Début des échéanciers</param>
    ''' <param name="echeancier_fin">Fin des échéanciers</param>
    ''' <param name="txTarifComDC_Per">Taux du tarif commercial deces par personne</param>
    ''' <param name="typeTarif">Type de Tarif</param>
    ''' <param name="termePret">Terme du Pret</param>
    ''' <param name="nb_cotisants">Nombre de cotisants</param>
    ''' <param name="age_fin_DC">Age final</param>
    ''' <returns></returns>
    ''' <remarks> Cette fonction permet de projeter les cotisations commerciales DC
    '''Elle renvoie un tableau à une dimension contenant les cotisations commerciales DC projetées
    ''' </remarks>
    Public Function Proj_Cotis_ComDC(ByVal nbPer As Integer, _
                                     ByVal CI As Double, _
                                     ByVal ages As Double(), _
                                     ByVal echeancier_deb As Double(), _
                                     ByVal echeancier_fin As Double(), _
                                     ByVal txTarifComDC_Per As Double, _
                                     ByVal typeTarif As TypeTarif, _
                                     ByVal termePret As TypeTerme, _
                                     ByVal nb_cotisants As Double(,), _
                                     ByVal age_fin_DC As Double) As Double()

        Dim cotis_comDC(nbPer - 1) As Double

        'Calcul de l'évolution des cotisations commerciales DC
        For n = 1 To nbPer
            If ages(n - 1) < age_fin_DC Then
                If typeTarif = Actuariat.TypeTarif.CapitalInitial Then
                    If termePret <> TypeTerme.AVANCE Then
                        cotis_comDC(n - 1) = txTarifComDC_Per * CI * nb_cotisants(n - 1, 1)
                    Else
                        cotis_comDC(n - 1) = txTarifComDC_Per * CI * nb_cotisants(n - 1, 0)
                    End If
                End If
                If typeTarif = Actuariat.TypeTarif.CSR Then
                    If termePret <> TypeTerme.AVANCE Then
                        cotis_comDC(n - 1) = txTarifComDC_Per * echeancier_deb(n - 1) * nb_cotisants(n - 1, 1)
                    Else
                        cotis_comDC(n - 1) = txTarifComDC_Per * echeancier_fin(n - 1) * nb_cotisants(n - 1, 0)
                    End If
                End If
            End If
        Next n

        Return cotis_comDC

    End Function

    ''' <summary>
    ''' Cette fonction permet de projeter les cotisations commerciales DC
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="cotis_comDC">Cotisation commercial deces</param>
    ''' <param name="fg">Frais de  Gestion</param>
    ''' <param name="remu_partenaire">Remuneration octroyee aux partenaire</param>
    ''' <returns></returns>
    ''' <remarks>Cette fonction permet de projeter les cotisations commerciales DC
    ''' Elle renvoie un tableau à une dimension contenant les cotisations commerciales DC projetées
    ''' </remarks>
    Public Function Proj_Cotis_TechDC(ByVal nbPer As Integer, _
                                      ByVal cotis_comDC As Double(), _
                                      ByVal fg As Double, _
                                      ByVal remu_partenaire As Double) As Double()

        Dim cotis_techDC(nbPer - 1) As Double

        'Calcul de l'évolution des primes techniques DC
        For n = 1 To nbPer
            cotis_techDC(n - 1) = cotis_comDC(n - 1) * (1 - fg - remu_partenaire)
        Next n

        Return cotis_techDC

    End Function

    ''' <summary>
    ''' Cette fonction permet de projeter les cotisations commerciales INC/INV
    ''' </summary> 
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="CI">Cappitall Initial</param>
    ''' <param name="ages">Ages</param>
    ''' <param name="echeancier_deb">Début des échéanciers</param>
    ''' <param name="echeancier_fin">Fin des échéanciers</param>
    ''' <param name="type_Tarif">Type de Tarif</param>
    ''' <param name="nb_cotisants">Nombre de cotisants</param>
    ''' <param name="txComINCINV_Per"></param>
    ''' <param name="type_amort">Type de Terme</param>
    ''' <param name="age_fin_INCINV">Age final</param>
    ''' <returns></returns>
    ''' <remarks> Cette fonction permet de projeter les cotisations commerciales INC/INV
    ''' Ajouter la possibilité de supprimer l'INCINV sur le segment
    ''' Elle renvoie un tableau à une dimension contenant les cotisations commerciales INC/INV projetées 
    ''' </remarks>
    Public Function Proj_Cotis_ComINCINV(ByVal nbPer As Integer, _
                                         ByVal CI As Double, _
                                         ByVal ages As Double(), _
                                         ByVal echeancier_deb As Double(), _
                                         ByVal echeancier_fin As Double(), _
                                         ByVal txComINCINV_Per As Double, _
                                         ByVal type_Tarif As TypeTarif, _
                                         ByVal type_amort As TypeTerme, _
                                         ByVal nb_cotisants As Double(,), _
                                         ByVal age_fin_INCINV As Double) As Double()

        Dim cotis_comINCINV(nbPer - 1) As Double

        'Calcul de l'évolution des cotisations commerciales DC
        For n = 1 To nbPer
            If ages(n - 1) < age_fin_INCINV Then
                If type_Tarif = TypeTarif.CapitalInitial Then
                    If type_amort <> TypeTerme.AVANCE Then
                        cotis_comINCINV(n - 1) = txComINCINV_Per * CI * nb_cotisants(n - 1, 1)
                    Else
                        cotis_comINCINV(n - 1) = txComINCINV_Per * CI * nb_cotisants(n - 1, 0)
                    End If
                End If
                If type_Tarif = TypeTarif.CSR Then
                    If type_amort <> TypeTerme.AVANCE Then
                        cotis_comINCINV(n - 1) = txComINCINV_Per * echeancier_deb(n - 1) * nb_cotisants(n - 1, 1)
                    Else
                        cotis_comINCINV(n - 1) = txComINCINV_Per * echeancier_fin(n - 1) * nb_cotisants(n - 1, 0)
                    End If
                End If
            End If
        Next n

        Return cotis_comINCINV

    End Function

    ''' <summary>
    ''' Cette fonction permet de projeter les cotisations commerciales DC
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="cotis_comINCINV"></param>
    ''' <param name="fg">Frais de gestion</param>
    ''' <param name="remu_partenaire"></param>
    ''' <param name="taxe">Taxe</param>
    ''' <returns></returns>
    ''' <remarks>Cette fonction permet de projeter les cotisations commerciales DC
    '''Elle renvoie un tableau à une dimension contenant les cotisations commerciales DC projetées  
    ''' </remarks>
    Public Function proj_Cotis_techINCINV(ByVal nbPer As Integer, _
                                          ByVal cotis_comINCINV As Double(), _
                                          ByVal fg As Double, _
                                          ByVal remu_partenaire As Double, _
                                          ByVal taxe As Double) As Double()

        Dim cotis_techINCINV(nbPer - 1) As Double

        'Calcul de l'évolution des primes techniques DC
        For n = 1 To nbPer
            cotis_techINCINV(n - 1) = (cotis_comINCINV(n - 1) / (1 + taxe)) * (1 - fg - remu_partenaire)
        Next n

        Return cotis_techINCINV

    End Function

#End Region

#Region "Sinistres"

    ''' <summary>
    ''' Proj_s the nb sin DC.
    ''' </summary>
    ''' <param name="nbPer">The nb per.</param>
    ''' <param name="ages">The ages.</param>
    ''' <param name="age_fin_DC">The age_fin_ DC.</param>
    ''' <param name="nb_cotisants">The nb_cotisants.</param>
    ''' <param name="tx_mortalite">The tx_mortalite.</param><returns></returns>
    Public Function Proj_NbSinDC(ByVal nbPer As Integer, _
                                 ByVal ages As Double(), _
                                 ByVal age_fin_DC As Double, _
                                 ByVal nb_cotisants As Double(,), _
                                 ByVal tx_mortalite As Double()) As Double()
        Dim sin_nbDC(nbPer - 1) As Double
        For i = 1 To nbPer
            If ages(i - 1) <= age_fin_DC Then
                sin_nbDC(i - 1) = nb_cotisants(i - 1, 0) * tx_mortalite(i - 1)
            End If
        Next i
        Return sin_nbDC

    End Function

    ''' <summary>
    ''' Permet de projeter la sinistralité de la garantie DC d'un contrat emprunteur
    ''' </summary>
    ''' <param name="nbPer">Nombre de période du prêt</param>
    ''' <param name="ages">Projection des âges à chaque période</param>
    ''' <param name="age_fin_DC">Age de fin de la garantie décès</param>
    ''' <param name="nb_cotisants">Nombre de cotisants à la souscription</param>
    ''' <param name="tx_mortalite">Taux de mortalité à chaque période</param>
    ''' <param name="echeancier_deb">Capitaux restants dûs au début de chaque période</param>
    ''' <param name="majo_sin_DC">Majoration prudentielle appliquée à la sinistralité</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_sin_regDC(ByVal nbPer As Integer, _
                                   ByVal ages As Double(), _
                                   ByVal age_fin_DC As Double, _
                                   ByVal nb_cotisants As Double(,), _
                                   ByVal tx_mortalite As Double(), _
                                   ByVal echeancier_deb As Double(), _
                                   ByVal majo_sin_DC As Double) As Double()
        Dim sin_rgDC(nbPer - 1) As Double
        For i = 1 To nbPer
            If ages(i - 1) <= age_fin_DC Then
                sin_rgDC(i - 1) = nb_cotisants(i - 1, 0) * tx_mortalite(i - 1) * echeancier_deb(i - 1) * (1 + majo_sin_DC)
            End If
        Next i
        Return sin_rgDC
    End Function

    ''' <summary>
    ''' Permet de projeter la sinistralité de la garantie INCAP/INVAL d'un contrat emprunteur
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="ages"></param>
    ''' <param name="age_fin_INCINV"></param>
    ''' <param name="nb_incap_inv"></param>
    ''' <param name="ech_pret"></param>
    ''' <param name="abattement_MNO"></param>
    ''' <param name="abattement_perte_rev"></param>
    ''' <param name="majo_sin_INCINV"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_sin_regINCINV(ByVal nbPer As Integer, _
                                       ByVal ages As Double(), _
                                       ByVal age_fin_INCINV As Double, _
                                       ByVal nb_incap_inv As Double(,), _
                                       ByVal ech_pret As Double, _
                                       ByVal abattement_MNO As Double, _
                                       ByVal abattement_perte_rev As Double, _
                                       ByVal majo_sin_INCINV As Double) As Double()
        Dim sin_rgINCINV(nbPer - 1) As Double

        For i = 1 To nbPer
            If ages(i - 1) <= age_fin_INCINV Then
                sin_rgINCINV(i - 1) = nb_incap_inv(i - 1, 3) * ech_pret * (1 - abattement_MNO) * (1 - abattement_perte_rev) * (1 + majo_sin_INCINV)
            End If
        Next i

        Return sin_rgINCINV
    End Function

#End Region

#Region "Provisions"


    ''' <summary>
    '''Cette fonction renvoie la provision de rente relative à nb_individus sinistrés à fin n
    '''entrés en sinistre au cours de la ième période.
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="nb_ind_INC_INV"></param>
    ''' <param name="evol_incap_inv"></param>
    ''' <param name="tx_mortalite"></param>
    ''' <param name="txRemb_per"></param>
    ''' <param name="mensualite"></param>
    ''' <param name="taux_tech"></param>
    ''' <param name="CI"></param>
    ''' <param name="txComINCINV_Per"></param>
    ''' <param name="fg"></param>
    ''' <param name="com_partenaire"></param>
    ''' <param name="taxe"></param>
    ''' <param name="abattement_MNO"></param>
    ''' <param name="abattement_perte_rev"></param>
    ''' <param name="majo_sin_INCINV"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_prov_rente(ByVal nbPer As Integer, _
                                    ByVal nb_ind_INC_INV As Double(,), _
                                    ByVal evol_incap_inv As Double(,), _
                                    ByVal tx_mortalite As Double(), _
                                    ByVal txRemb_per As Double, _
                                    ByVal mensualite As Double, _
                                    ByVal taux_tech As Double, _
                                    ByVal CI As Double, _
                                    ByVal txComINCINV_Per As Double, _
                                    ByVal fg As Double, _
                                    ByVal com_partenaire As Double, _
                                    ByVal taxe As Double, _
                                    ByVal abattement_MNO As Double, _
                                    ByVal abattement_perte_rev As Double, _
                                    ByVal majo_sin_INCINV As Double) As Double()

        Dim prov_rente(nbPer - 1) As Double
        Dim MensualiteAjustee As Double = mensualite * (1 - abattement_MNO) * (1 - abattement_perte_rev) * (1 + majo_sin_INCINV)
        Dim TxEscompte As Double = 1 / (1 + taux_tech)
        Dim PrimeTechniqueINCINV As Double = CI * txComINCINV_Per * (1 / (1 + taxe)) * (1 - fg - com_partenaire)

        'nb_ind_INC_INV(i,n) = nombre d'individus en incapacité/invalidité en fin de période n
        'et entrés en incapacité durant la période i.

        For dte_obs = 1 To nbPer

            'Ici, on a la somme de toutes les incap/inval des survenances passées
            'Il est nécessaire de faire un test pour supprimer les incap/inval n'ayant pas passé la période
            'de franchise
            'Ici, on calcule la valeur actuelle des sinistres à utiliser pour le calcul de la PM de rente
            For i = 1 To dte_obs - 3
                For k = dte_obs + 1 To nbPer
                    If k - i >= 3 Then
                        prov_rente(dte_obs - 1) = prov_rente(dte_obs - 1) + MensualiteAjustee * nb_ind_INC_INV(i - 1, k - 1) * (TxEscompte ^ (k - dte_obs))
                    End If
                Next k
            Next i

        Next dte_obs

        'La valeur actuelle des primes de la PM de rente à une date d'observation donnée est égale à la valeur actuelle des cotisations futures
        'des individus en sinistre à cette date, qu'ils restent ou non en sinistre.

        Dim evol_sinistres(nbPer - 1, nbPer - 1) As Double

        For dte_obs = 1 To nbPer
            evol_sinistres(dte_obs - 1, 0) = evol_incap_inv(dte_obs - 1, 3)
            For i = 2 To nbPer - dte_obs + 1
                evol_sinistres(dte_obs - 1, i - 1) = evol_sinistres(dte_obs - 1, i - 2) * (1 - tx_mortalite(dte_obs + i - 2)) * (1 - txRemb_per)
            Next i
        Next dte_obs

        For dte_obs = 1 To nbPer
            For i = 2 To nbPer
                prov_rente(dte_obs - 1) = prov_rente(dte_obs - 1) - (TxEscompte ^ (i - 1)) * (evol_sinistres(dte_obs - 1, i - 1)) * PrimeTechniqueINCINV
            Next i
        Next dte_obs

        Return prov_rente

    End Function

    ''' <summary>
    '''Cette fonction renvoie la provision pour risques croissants relatives aux individus valides en fin de période n
    '''Elle est donc égale à la valeur actuelle probable des primes à receoir de ces valides diminuée de la valeur actuelle des sinistrés futurs parmi ces valides
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="nb_ind_INC_INV"></param>
    ''' <param name="evol_incap_inv"></param>
    ''' <param name="tx_mortalite"></param>
    ''' <param name="txRemb_per"></param>
    ''' <param name="mensualite"></param>
    ''' <param name="taux_tech"></param>
    ''' <param name="CI"></param>
    ''' <param name="txComINCINV_Per"></param>
    ''' <param name="fg"></param>
    ''' <param name="com_partenaire"></param>
    ''' <param name="taxe"></param>
    ''' <param name="abattement_MNO"></param>
    ''' <param name="abattement_perte_rev"></param>
    ''' <param name="majo_sin_INCINV"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_prov_PPRC(ByVal nbPer As Integer, _
                                   ByVal nb_ind_INC_INV As Double(,), _
                                   ByVal evol_incap_inv As Double(,), _
                                   ByVal tx_mortalite As Double(), _
                                   ByVal txRemb_per As Double, _
                                   ByVal mensualite As Double, _
                                   ByVal taux_tech As Double, _
                                   ByVal CI As Double, _
                                   ByVal txComINCINV_Per As Double, _
                                   ByVal fg As Double, _
                                   ByVal com_partenaire As Double, _
                                   ByVal taxe As Double, _
                                   ByVal abattement_MNO As Double, _
                                   ByVal abattement_perte_rev As Double, _
                                   ByVal majo_sin_INCINV As Double) As Double()

        Dim prov_PPRC(nbPer - 1) As Double
        Dim MensualitePretAjustee As Double = mensualite * (1 - abattement_MNO) * (1 - abattement_perte_rev) * (1 + majo_sin_INCINV)
        Dim PrimeTechniqueINCINV As Double = CI * txComINCINV_Per * (1 / (1 + taxe)) * (1 - fg - com_partenaire)
        Dim TxEscompte As Double = (1 / (1 + taux_tech))

        'nb_ind_INC_INV(i,n) = nombre d'individus en incapacité/invalidité en fin de période n
        'et entrés en incapacité durant la période i.


        'Calcul de la valeure actuelle des sinistres à venir

        For dte_obs = 1 To nbPer

            'Ici, on fait la somme de toutes les incap/inval des survenances encore sous franchise et à venir
            'Les incap/inval n'ayant passé la période de franchise sont antérieures à dte_obs-2
            For i = Math.Max(dte_obs - 2, 1) To nbPer
                For k = dte_obs + 1 To nbPer
                    If k - i >= 3 Then
                        prov_PPRC(dte_obs - 1) = prov_PPRC(dte_obs - 1) + MensualitePretAjustee * nb_ind_INC_INV(i - 1, k - 1) * (TxEscompte ^ (k - dte_obs))
                    End If
                Next k
            Next i

        Next dte_obs

        'La valeur actuelle des primes de la PPRC à une date d'observation donnée est égale à la valeur actuelle des cotisations futures
        'des individus valides à la date d'observation, qu'ils entrent ou non en sinistre ensuite.

        Dim evol_sinistres(nbPer - 1, nbPer - 1) As Double

        For dte_obs = 1 To nbPer
            evol_sinistres(dte_obs - 1, 0) = evol_incap_inv(dte_obs - 1, 1)
            For i = 2 To nbPer - dte_obs + 1
                evol_sinistres(dte_obs - 1, i - 1) = evol_sinistres(dte_obs - 1, i - 2) * (1 - tx_mortalite(dte_obs + i - 2)) * (1 - txRemb_per)
            Next i
        Next dte_obs

        For dte_obs = 1 To nbPer
            For i = 2 To nbPer
                prov_PPRC(dte_obs - 1) = prov_PPRC(dte_obs - 1) - (TxEscompte ^ (i - 1)) * evol_sinistres(dte_obs - 1, i - 1) * PrimeTechniqueINCINV
            Next i
        Next dte_obs


        Return prov_PPRC

    End Function

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="cot_tech_DC"></param>
    ''' <param name="sin_regles_DC"></param>
    ''' <param name="tx_tech"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_PM_DC(ByVal nbPer As Integer, _
                               ByVal cot_tech_DC As Double(), _
                               ByVal sin_regles_DC As Double(), _
                               ByVal tx_tech As Double) As Double()


        Dim Prov_PM_DC(nbPer - 1) As Double

        For n = 1 To nbPer

            For k = n + 1 To nbPer
                Prov_PM_DC(n - 1) = Prov_PM_DC(n - 1) - cot_tech_DC(k - 1) / ((1 + tx_tech) ^ (k - n)) + sin_regles_DC(k - 1) / ((1 + tx_tech) ^ (k - n - 1 / 2))
            Next k

        Next n

        Return Prov_PM_DC

    End Function

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="cot_tech_INCINV"></param>
    ''' <param name="sin_regles_INCINV"></param>
    ''' <param name="txtech"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_PM_INCINV(ByVal nbPer As Integer, _
                                   ByVal cot_tech_INCINV As Double(), _
                                   ByVal sin_regles_INCINV As Double(), _
                                   ByVal txtech As Double) As Double()


        Dim Prov_PM_INCINV(nbPer - 1) As Double

        For n = 1 To nbPer

            For k = n + 1 To nbPer
                Prov_PM_INCINV(n - 1) = Prov_PM_INCINV(n - 1) - cot_tech_INCINV(k - 1) / ((1 + txtech) ^ (k - n)) + sin_regles_INCINV(k - 1) / ((1 + txtech) ^ (k - n))
            Next k

        Next n

        Return Prov_PM_INCINV

    End Function

#End Region

#Region "Capitaux sous risque"

    ''' <summary>
    ''' Projection des capitaux sous risques
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="ech_fin">Echeance Final</param>
    ''' <param name="nb_cot">Nombre de  cotisants</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_CSR_DC(ByVal nbPer As Integer, _
                                ByVal ech_fin As Double(), _
                                ByVal nb_cot As Double(,)) As Double()
        Dim CSR_DC_fin(nbPer - 1) As Double
        For i = 1 To nbPer
            CSR_DC_fin(i - 1) = nb_cot(i - 1, 1) * ech_fin(i - 1)
        Next i
        Return CSR_DC_fin
    End Function

#End Region

#Region "Marge de solvabilité règlementaire VIE"

    ''' <summary>
    ''' Projection de la marge de solvabilité VIE
    ''' </summary>
    ''' <param name="nbPer">Nombre de periodes</param>
    ''' <param name="CSR_DC">Capitaux sous risque DECES</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Proj_MSR_vie( _
        ByVal nbPer As Integer, _
        ByVal CSR_DC As Double()) As Double()

        Dim MSR_vie(nbPer - 1) As Double
        Dim duree_residuelle As Double, MSR_vie_PM As Double, MSR_vie_CSR As Double, d As Double


        For i As Integer = 1 To nbPer

            duree_residuelle = (nbPer - i) / 12
            If duree_residuelle > 5 Then d = 0.003
            If duree_residuelle <= 5 And duree_residuelle > 3 Then d = 0.0015
            If duree_residuelle <= 3 Then d = 0.001
            MSR_vie_CSR = CSR_DC(i - 1) * d

            MSR_vie(i - 1) = MSR_vie_CSR + MSR_vie_PM

        Next i

        Return MSR_vie

    End Function
#End Region

#Region "Version Modèle EXCEL"

#Region "Conversion d'unité - remplacé par les classes de contrôle"
    ''' <summary>
    '''  Cette fonction, ajoute à un objet proj_empr dont les simulations mensuelles sont déjà réalisées,
    ''' les projections des variables annuelles
    ''' </summary>
    ''' <param name="paramIHM">Parametre</param>
    ''' <returns></returns>
    ''' <remarks>INDICES A REVOIR</remarks>
    Public Function Param_Proj_En_cours(ByVal paramIHM As Param_Proj_Empr) As Param_Proj_Empr
        param_proj_En_cours = New Param_Proj_Empr()

        Dim result As New Param_Proj_Empr

        'Initialisation des paramètres utilisés par le moteur de projection emprunteur
        result.txRemb_per = Mensualise_tx(paramIHM.txRemb_per, 0)
        result.fg = paramIHM.fg
        result.ratio_fds_propres_alloues = paramIHM.ratio_fds_propres_alloues
        result.com_partenaire = paramIHM.com_partenaire
        result.nbEmprInit = paramIHM.nbEmprInit
        result.pres_INCINV = paramIHM.pres_INCINV
        result.age_fin_DC = paramIHM.age_fin_DC
        result.age_fin_INCINV = paramIHM.age_fin_INCINV
        result.txEntINCINV = paramIHM.txEntINCINV
        result.franchise_INCINV = paramIHM.franchise_INCINV
        result.abattement_MNO = paramIHM.abattement_MNO
        result.abattement_perte_rev = paramIHM.abattement_perte_rev
        result.tarif_PTIA = paramIHM.tarif_PTIA
        result.chgt_secur_tble_INCINV = paramIHM.chgt_secur_tble_INCINV
        result.majo_sin_DC = paramIHM.majo_sin_DC
        result.majo_sin_INCINV = paramIHM.majo_sin_INCINV
        result.type_Tarif = paramIHM.type_Tarif
        result.per = paramIHM.per
        result.type_amort = paramIHM.type_amort
        result.type_pret = paramIHM.type_pret
        result.nbPer = paramIHM.nbPer * 12
        result.txComDC_Per = Mensualise_tx(paramIHM.txComDC_Per, 0)
        result.txComINCINV_Per = Mensualise_tx(paramIHM.txComINCINV_Per, 0)
        result.txNomPer = Mensualise_tx(paramIHM.txNomPer, 0)
        result.CI = paramIHM.CI
        result.sel_medic = paramIHM.sel_medic
        result.ageInit = paramIHM.ageInit
        result.sexe = paramIHM.sexe
        result.taxe = paramIHM.taxe
        result.txtech = Mensualise_tx(paramIHM.txtech, 1)
        result.selMedicale = paramIHM.selMedicale
        'Fonction PMT calcule les montants d'échéances d'un emprunt
        '   - paramètre 1 : taux nominal de la période
        '   - paramètre 2 : nombre de périodes
        '   - paramètre 3 : capital emprunté
        '   - paramètre 4 : valeure capitalisée (0 si le montant restant à rembourser au terme = 0)
        '   - paramètre 5 : 0 ou omis = Remboursement à terme / 1 = Remboursement d'avance
        result.ech_pret = -Pmt(param_proj_En_cours.txNomPer, param_proj_En_cours.nbPer, param_proj_En_cours.CI, 0, 0)

        Return result
    End Function
#End Region

    ''' <summary>
    ''' Cette fonction, ajoute à un objet proj_empr dont les simulations mensuelles sont déjà réalisées,
    '''les projections des variables annuelles
    ''' </summary>
    ''' <param name="p">Projection</param>
    ''' <remarks>
    '''INDICES A REVOIR
    ''' </remarks>
    Public Sub Moteur_Proj_Empr_Annu(ByVal p As Proj_Empr)

        Dim MSR_vie_annu(), CSR_DC_fin_annu(), cotis_Com_DC_annu(), cotis_Com_INCINV_annu(), sin_regles_DC_annu(), sin_regles_INCINV_annu()
        Dim Prov_PM_DC_annu(), Prov_PM_INCINV_annu(), Prov_PMRente_INCINV_annu(), Prov_PPRC_INCINV_annu()
        Dim nbAnnees As Integer

        nbAnnees = p.Projections.num_annee(p.Parametres.nbPer)

        ReDim CSR_DC_fin_annu(nbAnnees), cotis_Com_DC_annu(nbAnnees), cotis_Com_INCINV_annu(nbAnnees)
        ReDim sin_regles_DC_annu(nbAnnees), sin_regles_INCINV_annu(nbAnnees)
        ReDim Prov_PM_DC_annu(nbAnnees), Prov_PM_INCINV_annu(nbAnnees), Prov_PMRente_INCINV_annu(nbAnnees), Prov_PPRC_INCINV_annu(nbAnnees), MSR_vie_annu(nbAnnees)

        With p

            For i = 1 To .Parametres.nbPer

                CSR_DC_fin_annu(.Projections.num_annee(i)) = .Projections.CSR_DC(i)
                Prov_PM_DC_annu(.Projections.num_annee(i)) = .Projections.Prov_PM_DC(i)
                Prov_PM_INCINV_annu(.Projections.num_annee(i)) = .Projections.Prov_PM_INCINV(i)
                Prov_PMRente_INCINV_annu(.Projections.num_annee(i)) = .Projections.Prov_PMRente_INCINV(i)
                Prov_PPRC_INCINV_annu(.Projections.num_annee(i)) = .Projections.Prov_PPRC_INCINV(i)
                MSR_vie_annu(.Projections.num_annee(i)) = .Projections.MSR_vie(i)

                cotis_Com_DC_annu(.Projections.num_annee(i)) = cotis_Com_DC_annu(.Projections.num_annee(i)) + .Projections.cotis_Com_DC(i)
                cotis_Com_INCINV_annu(.Projections.num_annee(i)) = cotis_Com_INCINV_annu(.Projections.num_annee(i)) + .Projections.cotis_Com_INCINV(i)
                sin_regles_DC_annu(.Projections.num_annee(i)) = sin_regles_DC_annu(.Projections.num_annee(i)) + .Projections.sin_regles_DC(i)
                sin_regles_INCINV_annu(.Projections.num_annee(i)) = sin_regles_INCINV_annu(.Projections.num_annee(i)) + .Projections.sin_regles_INCINV(i)

            Next i

            With .Projections

                .cotis_Com_DC_annu = cotis_Com_DC_annu
                .cotis_Com_INCINV_annu = cotis_Com_INCINV_annu
                .CSR_DC_fin_annu = CSR_DC_fin_annu
                .Prov_PM_DC_annu = Prov_PM_DC_annu
                .Prov_PM_INCINV_annu = Prov_PM_INCINV_annu
                .Prov_PMRente_INCINV_annu = Prov_PMRente_INCINV_annu
                .Prov_PPRC_INCINV_annu = Prov_PPRC_INCINV_annu
                .sin_regles_DC_annu = sin_regles_DC_annu
                .sin_regles_INCINV_annu = sin_regles_INCINV_annu
                .MSR_vie_annu = MSR_vie_annu

            End With

        End With

    End Sub

#End Region

End Module
